package com.join.mybatis.base.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.join.mybatis.MyBusinessException;
import com.join.mybatis.MyBaseMapperNotFoundException;
import com.join.mybatis.base.MyBaseMapper;
import com.join.mybatis.base.MyBaseService;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.Consumer;

/**
 * @author chengang
 */
public class MyBaseServiceImpl<T extends BaseMapper<S>,S> extends ServiceImpl<T,S> implements MyBaseService<S> {


    @Override
    public IPage<S> query(IPage<S> page, LinkedHashMap<String, Object> map) {
        return super.page(page, processQueryWrapper(map));
    }

    @Override
    public IPage<S> queryByJoin(IPage<S> page, LinkedHashMap<String, Object> map) {

        return queryByJoin(page,null,map);
    }

    @Override
    public IPage<S> queryByJoin(IPage<S> page, Consumer<QueryWrapper<S>> consumer, LinkedHashMap<String, Object> map) {
        QueryWrapper<S> sQueryWrapper = processQueryWrapper(map, true);
        return queryByJoin(page,consumer,sQueryWrapper );
    }

    @Override
    public IPage<S> queryByJoin(IPage<S> page,QueryWrapper<S> queryWrapper) {

        return queryByJoin(page,null,queryWrapper);
    }

    @Override
    public IPage<S> queryByJoin(IPage<S> page, Consumer<QueryWrapper<S>> consumer,QueryWrapper<S> queryWrapper) {
        if (!(baseMapper instanceof MyBaseMapper)) {
            throw new MyBaseMapperNotFoundException("extends myBaseMapper to achieve multi-table query function");
        }
        if(Objects.nonNull(consumer))consumer.accept(queryWrapper);
        return ((MyBaseMapper<S>) baseMapper).selectPageByJoin(page,queryWrapper );
    }

    @Override
    public <E extends IPage<S>> E page(E page, Wrapper<S> queryWrapper) {
        if (queryWrapper != null && queryWrapper instanceof QueryWrapper) {
            queryWrapper = ((QueryWrapper<S>) queryWrapper).orderByDesc("update_time");
        }
        return super.page(page, queryWrapper);
    }

    @Override
    public List<S> list(LinkedHashMap<String, Object> map, String... orderBy) {
        if (ArrayUtil.isNotEmpty(orderBy)) {
            return super.list(processQueryWrapper(map).orderBy(true, false, orderBy));
        }
        return super.list(processQueryWrapper(map));
    }

    @Override
    public List<S> list(LinkedHashMap<String, Object> map, Boolean isAsc, String... orderBy) {
        if (ArrayUtil.isNotEmpty(orderBy)) {
            return super.list(processQueryWrapper(map).orderBy(true, isAsc, orderBy));
        }
        return super.list(processQueryWrapper(map));
    }

    @Override
    public List<S> listByJoin(LinkedHashMap<String, Object> map, String... orderBy) {
        if (ArrayUtil.isNotEmpty(orderBy)) {
            return listByJoin(processQueryWrapper(map, true).orderBy(true, false, orderBy));
        }
        return listByJoin(processQueryWrapper(map, true));
    }

    @Override
    public List<S> listByJoin(QueryWrapper<S> queryWrapper, String... orderBy) {
        return listByJoin(queryWrapper,null,false,orderBy);
    }
    @Override
    public List<S> listByJoin(QueryWrapper<S> queryWrapper,Boolean isAsc, String... orderBy) {
        return listByJoin(queryWrapper,null,isAsc,orderBy);
    }

    public List<S> listByJoin(QueryWrapper<S> queryWrapper,Consumer<QueryWrapper<S>> consumer , String... orderBy){
        return listByJoin(queryWrapper,null,false,orderBy);
    }
    /**
     * orderBy 默认是desc排序例如create_time,update_time
     * @param queryWrapper
     * @param consumer
     * @param orderBy
     * @return
     */
    @Override
    public List<S> listByJoin(QueryWrapper<S> queryWrapper,Consumer<QueryWrapper<S>> consumer,Boolean isAsc, String... orderBy) {
        if (!(baseMapper instanceof MyBaseMapper)) {
            throw new MyBaseMapperNotFoundException("extends myBaseMapper to achieve multi-table query function");
        }
        if(Objects.nonNull(consumer))consumer.accept(queryWrapper);
        if (ArrayUtil.isNotEmpty(orderBy)) {
            return ((MyBaseMapper<S>) baseMapper).selectListByJoin(queryWrapper.orderBy(true, isAsc, orderBy));
        }
        return ((MyBaseMapper<S>) baseMapper).selectListByJoin(queryWrapper);
    }

    @Override
    public S getByIdJoin(String id) {
        if (!(baseMapper instanceof MyBaseMapper)) {
            throw new MyBaseMapperNotFoundException("extends myBaseMapper to achieve multi-table query function");
        }
        LinkedHashMap param=new LinkedHashMap(){{put("id:eq",id);}};
        List<S> selectListByJoin = ((MyBaseMapper<S>) baseMapper).selectListByJoin(processQueryWrapper(param, true));
        if(selectListByJoin.isEmpty()){
            return null;
        }

        return selectListByJoin.get(0);
    }


    protected Class<S> getEntityClazz() {
        return (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
    }

    private QueryWrapper<S> processQueryWrapper(LinkedHashMap<String, Object> map, Boolean joinFlag) {
        if(Objects.isNull(map)){
            return new QueryWrapper<S>();
        }
        //删除分页参数
        map.remove("pageNum");
        map.remove("pageSize");
        //删除排序参数
        String sortValue = "";
        if (map.containsKey("orderBy")) {
            sortValue = map.get("orderBy") + "";
            map.remove("orderBy");
        }

        QueryWrapper<S> queryWrapper = new QueryWrapper<>();
        map.forEach((k, v) -> {
            Object o = map.get(k);
            //验证 如果参数是数组，数组不能为空！
            if (o instanceof Collection && CollectionUtil.isEmpty((Collection) o)) {
                return;
            }
            if (o instanceof String && StringUtils.isBlank((CharSequence) o)) {
                return;
            }
            if (Objects.isNull(v)||StrUtil.isBlank(v+"")) {
                return;
            }
            String key = k;
            String op = "LIKE";
            if (k.contains(":")) {
                key = k.split(":")[0];
                op = k.split(":")[1] == null ? "LIKE" : k.split(":")[1];
            }
            String finalOp = op;
            String finalKey = finalKey(key,joinFlag);
            if (finalKey.contains(",")) {
                queryWrapper.and(wrapper -> {
                    Arrays.stream(finalKey.split(",")).forEach(item -> {
                        //如果value是个list，默认是in查询，不支持其他情况
                        if (o instanceof Collection) {
                            if (finalOp.equalsIgnoreCase("NOT")) {
                                queryWrapper.or().notIn(item, (Collection) o);
                            }else{
                                queryWrapper.or().in(item, (Collection) o);
                            }
                        } else {
                            if (finalOp.equalsIgnoreCase("EQ")) {
                                wrapper.or().eq(item, o);
                            } else if (finalOp.equalsIgnoreCase("NEQ")) {
                                wrapper.or().ne(item, o);
                            } else if (finalOp.equalsIgnoreCase("GT")) {
                                wrapper.or().ge(item, o);
                            } else if (finalOp.equalsIgnoreCase("LT")) {
                                wrapper.or().le(item, o);
                            } else if(finalOp.equalsIgnoreCase("LKL")){
                                wrapper.or().likeLeft(finalKey,o);
                            }else if(finalOp.equalsIgnoreCase("LKR")){
                                wrapper.or().likeRight(finalKey,o);
                            }else {
                                wrapper.or().like(item, o);
                            }
                        }
                    });
                });
            } else {
                if (o instanceof Collection) {
                    if (finalOp.equalsIgnoreCase("NOT")) {
                        queryWrapper.notIn(finalKey, (Collection) o);
                    }else{
                        queryWrapper.in(finalKey, (Collection) o);
                    }
                } else {
                    if (finalOp.equalsIgnoreCase("EQ")) {
                        queryWrapper.eq(finalKey, o);
                    } else if (finalOp.equalsIgnoreCase("NEQ")) {
                        queryWrapper.ne(finalKey, o);
                    } else if (finalOp.equalsIgnoreCase("GT")) {
                        queryWrapper.ge(finalKey, o);
                    } else if (finalOp.equalsIgnoreCase("LT")) {
                        queryWrapper.le(finalKey, o);
                    }  else if(finalOp.equalsIgnoreCase("LKL")){
                        queryWrapper.likeLeft(finalKey,o);
                    }else if(finalOp.equalsIgnoreCase("LKR")){
                        queryWrapper.likeRight(finalKey,o);
                    }else {
                        queryWrapper.like(finalKey, o);
                    }
                }
            }
        });
        if (StrUtil.isNotBlank(sortValue)) {
            String[] sortCols = sortValue.split(",");
            for (String sortCol : sortCols) {
                String[] sorts = sortCol.split(":");
                boolean isAsc = sorts.length < 2 ? true : sorts[1].equalsIgnoreCase("asc") ? true : false;
                queryWrapper.orderBy(true, isAsc, sorts[0]);
            }
        }
        return queryWrapper;
    }

    private String finalKey(String key, Boolean joinFlag) {
        String finalKey=key;
        if(joinFlag){
            //开启多表查询
            Type type = this.getClass().getGenericSuperclass();
            Type[] typeArr = ((ParameterizedType) type).getActualTypeArguments();
            Class<S> clazz = (Class<S>) (typeArr[1]);
            if(!(key.indexOf(".")>-1)){
                String tableName;
                if(clazz.isAnnotationPresent(TableName.class)){
                    tableName=StrUtil.toCamelCase(clazz.getAnnotation(TableName.class).value());
                }else{
                    tableName=StrUtil.lowerFirst(clazz.getSimpleName());
                }
                finalKey= tableName+"."+StrUtil.toUnderlineCase(finalKey);
            }else{
                String[] sp=key.split("\\.");
                finalKey=sp[0]+"."+StrUtil.toUnderlineCase(sp[1]);
            }
        }
        return finalKey;
    }

    protected QueryWrapper<S> processQueryWrapper(LinkedHashMap<String, Object> map) {

        return processQueryWrapper(map, false);
    }

}
